{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f6c93f2c-3394-42bd-a9a3-8b58a3679a3e",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/bayuan/miniconda3/envs/deepseek/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7e9d40bd-d45f-49ae-9456-e00296316669",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "768\n",
      "[-0.00993222  0.04682298 -0.03675228 -0.08068266 -0.02617284  0.0037349\n",
      "  0.00990155 -0.08762875 -0.01553682  0.05377049]\n"
     ]
    }
   ],
   "source": [
    "test_embedding = embedding_model.encode_queries([\"不动产如何转让\"])[0]\n",
    "embedding_dim = len(test_embedding)\n",
    "print(embedding_dim)\n",
    "print(test_embedding[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6947ab4-65f2-48f2-90d4-79797d132841",
   "metadata": {},
   "source": [
    "# 数据加载到Milvus"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ee56885-12dd-4343-85d3-333b33ebd54b",
   "metadata": {},
   "source": [
    "## 创建Collection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "91ef8ec2-f722-416a-a6ab-5257c0ea38c8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymilvus import MilvusClient\n",
    "\n",
    "milvus_client = MilvusClient(uri=\"./milvus_demo.db\")\n",
    "\n",
    "collection_name = \"rag_mfd_collection\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "dd8c252f-5566-4979-9c4e-5d3ac845738d",
   "metadata": {},
   "outputs": [],
   "source": [
    "if milvus_client.has_collection(collection_name):\n",
    "    milvus_client.drop_collection(collection_name)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2311b91d-a055-46da-b8fa-1c0eca3994aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "milvus_client.create_collection(\n",
    "    collection_name=collection_name,\n",
    "    dimension=embedding_dim,\n",
    "    metric_type=\"IP\",  # 内积距离\n",
    "    consistency_level=\"Strong\",  # 支持的值为 (`\"Strong\"`, `\"Session\"`, `\"Bounded\"`, `\"Eventually\"`)。更多详情请参见 https://milvus.io/docs/consistency.md#Consistency-Level。\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8298f061-ae60-4e4f-acf0-bab06e14e444",
   "metadata": {},
   "source": [
    "## 插入数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9cebc060-fb49-4903-9a98-1af694581986",
   "metadata": {},
   "source": [
    "### 准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "02abfe78-94a5-4d0c-a56b-75bb3288a4c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "text_lines = []\n",
    "\n",
    "with open(\"mfd.md\", \"r\") as file:\n",
    "    file_text = file.read()\n",
    "\n",
    "text_lines += file_text.split(\"# \")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "24e632e1-94f6-4ff3-8ef1-5fd548f4b611",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Creating embeddings: 100%|██████████| 30/30 [00:00<00:00, 503316.48it/s]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'insert_count': 30, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], 'cost': 0}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "data = []\n",
    "\n",
    "doc_embeddings = embedding_model.encode_documents(text_lines)\n",
    "\n",
    "for i, line in enumerate(tqdm(text_lines, desc=\"Creating embeddings\")):\n",
    "    data.append({\"id\": i, \"vector\": doc_embeddings[i], \"text\": line})\n",
    "\n",
    "milvus_client.insert(collection_name=collection_name, data=data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ae4e03b-e78a-4d62-b19a-ec7ec5ea1aa6",
   "metadata": {},
   "source": [
    "## 准备LLM"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37898ba6-dd1b-45c1-a975-99312da52029",
   "metadata": {},
   "source": [
    "### 准备API_KEY"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e6da3abb-b043-4067-9a7d-003a85a58527",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "# 从环境变量获取 DeepSeek API Key\n",
    "api_key = os.getenv(\"DEEPSEEK_API_KEY\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff91646e-3c94-441b-9f1f-b330da9929ca",
   "metadata": {},
   "source": [
    "### 准备api client"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "35b3db48-1537-47e5-aad2-0601f0a40688",
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "\n",
    "deepseek_client = OpenAI(\n",
    "    api_key=api_key,\n",
    "    base_url=\"https://api.deepseek.com/v1\",  # DeepSeek API 的基地址\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a86179c-8367-4f40-bdf8-8428f3e25caf",
   "metadata": {},
   "source": [
    "## RAG"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "851b3fc3-8292-4d12-9da8-4030d02a25a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "question = \"私人物品什么情况下能被征用\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "54c48369-23c7-42ac-8daa-3412263f6cb6",
   "metadata": {},
   "outputs": [],
   "source": [
    "search_res = milvus_client.search(\n",
    "    collection_name=collection_name,\n",
    "    data=embedding_model.encode_queries(\n",
    "        [question]\n",
    "    ),  # 将问题转换为嵌入向量\n",
    "    limit=3,  # 返回前3个结果\n",
    "    search_params={\"metric_type\": \"IP\", \"params\": {}},  # 内积距离\n",
    "    output_fields=[\"text\"],  # 返回 text 字段\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "07304ea2-0f89-4ddf-a03a-668ae24d736b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "    [\n",
      "        \"第三章 合同的变更和转让\\n\\n**第五百四十八条** 当事人协商一致，可以变更合同。\\n\\n**第五百四十九条** 当事人对合同变更的内容约定不明确的，推定为未变更。\\n\\n**第五百五十条** 债权人可以将合同的权利全部或者部分转让给第三人，但是有下列情形之一的除外：\\n（一）根据合同性质不得转让；\\n（二）按照当事人约定不得转让；\\n（三）依照法律规定不得转让。\\n债权人转让权利的，应当通知债务人。未经通知，该转让对债务人不发生效力。\\n\\n**第五百五十一条** 债权人转让权利的，受让人取得与债权有关的从权利，但是该从权利专属于债权人自身的除外。\\n\\n**第五百五十二条** 债务人将合同的义务全部或者部分转让给第三人的，应当经债权人同意。\\n\\n**第五百五十三条** 债务人转让义务的，新债务人可以主张原债务人对债权人的抗辩。\\n新债务人承担债务的，应当承担与主债务有关的从债务，但是该从债务专属于原债务人自身的除外。\\n\\n**第五百五十四条** 当事人一方经对方同意，可以将自己在合同中的权利和义务一并转让给第三人。\\n\\n**第五百五十五条** 权利和义务一并转让的，适用债权转让、债务转让的有关规定。\\n\\n**第五百五十六条** 合同变更的，不影响当事人请求损害赔偿的权利。\\n\\n###\",\n",
      "        0.6202715635299683\n",
      "    ],\n",
      "    [\n",
      "        \"第五章 占有\\n\\n**第四百七十一条** 占有是指对物事实上的控制和支配。\\n\\n**第四百七十二条** 占有可以分为直接占有和间接占有。\\n直接占有是指直接对物进行控制和支配。\\n间接占有是指通过他人对物进行控制和支配。\\n\\n**第四百七十三条** 占有的取得和消灭，适用本法有关物权设立和消灭的规定。\\n\\n**第四百七十四条** 占有人合法占有动产的，善意取得人取得该动产所有权。\\n占有人非法占有动产的，善意取得人取得该动产所有权。\\n\\n**第四百七十五条** 占有物毁损、灭失的，占有人应当承担赔偿责任。\\n占有人善意占有物的，不承担赔偿责任。\\n占有人恶意占有物的，应当承担赔偿责任。\\n\\n**第四百七十六条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百七十七条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百七十八条** 占有物毁损、灭失的，占有人应当承担赔偿责任。\\n占有人善意占有物的，不承担赔偿责任。\\n占有人恶意占有物的，应当承担赔偿责任。\\n\\n**第四百七十九条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百八十条** 占有物被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n------\\n\\n##\",\n",
      "        0.6135169267654419\n",
      "    ],\n",
      "    [\n",
      "        \"第六节 地役权\\n\\n**第三百八十八条** 地役权人有权依照合同约定，利用他人的不动产，以提高自己的不动产的效益。\\n前款所称他人的不动产为供役地，自己的不动产为需役地。\\n\\n**第三百八十九条** 地役权合同一般包括下列条款：\\n（一）当事人的姓名或者名称和住所；\\n（二）供役地和需役地的位置；\\n（三）地役权的目的和期限；\\n（四）利用供役地的方式；\\n（五）报酬及其支付方式；\\n（六）争议解决方式。\\n\\n**第三百九十条** 设立地役权，当事人应当依照法律规定办理登记。\\n未经登记，不得对抗善意第三人。\\n\\n**第三百九十一条** 地役权人有权依照合同约定，利用供役地，以提高需役地的效益。\\n地役权人行使权利，不得损害供役地权利人的合法权益。\\n\\n**第三百九十二条** 供役地权利人应当按照约定，允许地役权人利用其土地。\\n供役地权利人不得妨碍地役权人行使权利。\\n\\n**第三百九十三条** 地役权期限届满或者地役权人放弃地役权的，地役权消灭。\\n地役权消灭的，登记机构应当依法办理注销登记。\\n\\n**第三百九十四条** 地役权人应当按照合同约定支付报酬。\\n地役权人应当按照合同约定，以合理的方式利用供役地。\\n\\n**第三百九十五条** 地役权不得单独转让。土地承包经营权、建设用地使用权、宅基地使用权等权利转让的，地役权一并转让。\\n地役权不得单独抵押。土地承包经营权、建设用地使用权、宅基地使用权等权利抵押的，地役权一并抵押。\\n\\n**第三百九十六条** 地役权存续期间，供役地权利人将供役地转让、出租或者抵押的，地役权不受影响。\\n\\n**第三百九十七条** 地役权因供役地权利人将供役地转让、出租或者抵押而消灭的，地役权人有权请求赔偿损失。\\n地役权因供役地权利人将供役地转让、出租或者抵押而消灭的，地役权人可以向供役地权利人请求损害赔偿。\\n\\n**第三百九十八条** 地役权人有权依照合同约定，利用他人的不动产，以提高自己的不动产的效益。\\n前款所称他人的不动产为供役地，自己的不动产为需役地。\\n\\n###\",\n",
      "        0.6055376529693604\n",
      "    ]\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "\n",
    "retrieved_lines_with_distances = [\n",
    "    (res[\"entity\"][\"text\"], res[\"distance\"]) for res in search_res[0]\n",
    "]\n",
    "print(json.dumps(retrieved_lines_with_distances, indent=4, ensure_ascii=False))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08fe719c-99f3-451b-9410-5424ebbb6d62",
   "metadata": {},
   "source": [
    "## 使用 LLM 获取 RAG 响应"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "d05837bd-21a8-41a1-9ca0-38d70858d112",
   "metadata": {},
   "outputs": [],
   "source": [
    "context = \"\\n\".join(\n",
    "    [line_with_distance[0] for line_with_distance in retrieved_lines_with_distances]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "b5c50746-c89b-4e76-9e4c-1c86642eab2f",
   "metadata": {},
   "outputs": [],
   "source": [
    "SYSTEM_PROMPT = \"\"\"\n",
    "Human: 你是一个 AI 助手。你能够从提供的上下文段落片段中找到问题的答案。\n",
    "\"\"\"\n",
    "USER_PROMPT = f\"\"\"\n",
    "请使用以下用 <context> 标签括起来的信息片段来回答用 <question> 标签括起来的问题。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question}\n",
    "</question>\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "3ddeda51-ab2b-42fc-b7c0-8561a03f9a22",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n请使用以下用 <context> 标签括起来的信息片段来回答用 <question> 标签括起来的问题。\\n<context>\\n第三章 合同的变更和转让\\n\\n**第五百四十八条** 当事人协商一致，可以变更合同。\\n\\n**第五百四十九条** 当事人对合同变更的内容约定不明确的，推定为未变更。\\n\\n**第五百五十条** 债权人可以将合同的权利全部或者部分转让给第三人，但是有下列情形之一的除外：\\n（一）根据合同性质不得转让；\\n（二）按照当事人约定不得转让；\\n（三）依照法律规定不得转让。\\n债权人转让权利的，应当通知债务人。未经通知，该转让对债务人不发生效力。\\n\\n**第五百五十一条** 债权人转让权利的，受让人取得与债权有关的从权利，但是该从权利专属于债权人自身的除外。\\n\\n**第五百五十二条** 债务人将合同的义务全部或者部分转让给第三人的，应当经债权人同意。\\n\\n**第五百五十三条** 债务人转让义务的，新债务人可以主张原债务人对债权人的抗辩。\\n新债务人承担债务的，应当承担与主债务有关的从债务，但是该从债务专属于原债务人自身的除外。\\n\\n**第五百五十四条** 当事人一方经对方同意，可以将自己在合同中的权利和义务一并转让给第三人。\\n\\n**第五百五十五条** 权利和义务一并转让的，适用债权转让、债务转让的有关规定。\\n\\n**第五百五十六条** 合同变更的，不影响当事人请求损害赔偿的权利。\\n\\n###\\n第五章 占有\\n\\n**第四百七十一条** 占有是指对物事实上的控制和支配。\\n\\n**第四百七十二条** 占有可以分为直接占有和间接占有。\\n直接占有是指直接对物进行控制和支配。\\n间接占有是指通过他人对物进行控制和支配。\\n\\n**第四百七十三条** 占有的取得和消灭，适用本法有关物权设立和消灭的规定。\\n\\n**第四百七十四条** 占有人合法占有动产的，善意取得人取得该动产所有权。\\n占有人非法占有动产的，善意取得人取得该动产所有权。\\n\\n**第四百七十五条** 占有物毁损、灭失的，占有人应当承担赔偿责任。\\n占有人善意占有物的，不承担赔偿责任。\\n占有人恶意占有物的，应当承担赔偿责任。\\n\\n**第四百七十六条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百七十七条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百七十八条** 占有物毁损、灭失的，占有人应当承担赔偿责任。\\n占有人善意占有物的，不承担赔偿责任。\\n占有人恶意占有物的，应当承担赔偿责任。\\n\\n**第四百七十九条** 占有被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n**第四百八十条** 占有物被侵夺的，占有人有权请求返还原物。\\n占有物毁损、灭失的，占有人有权请求赔偿损失。\\n\\n------\\n\\n##\\n第六节 地役权\\n\\n**第三百八十八条** 地役权人有权依照合同约定，利用他人的不动产，以提高自己的不动产的效益。\\n前款所称他人的不动产为供役地，自己的不动产为需役地。\\n\\n**第三百八十九条** 地役权合同一般包括下列条款：\\n（一）当事人的姓名或者名称和住所；\\n（二）供役地和需役地的位置；\\n（三）地役权的目的和期限；\\n（四）利用供役地的方式；\\n（五）报酬及其支付方式；\\n（六）争议解决方式。\\n\\n**第三百九十条** 设立地役权，当事人应当依照法律规定办理登记。\\n未经登记，不得对抗善意第三人。\\n\\n**第三百九十一条** 地役权人有权依照合同约定，利用供役地，以提高需役地的效益。\\n地役权人行使权利，不得损害供役地权利人的合法权益。\\n\\n**第三百九十二条** 供役地权利人应当按照约定，允许地役权人利用其土地。\\n供役地权利人不得妨碍地役权人行使权利。\\n\\n**第三百九十三条** 地役权期限届满或者地役权人放弃地役权的，地役权消灭。\\n地役权消灭的，登记机构应当依法办理注销登记。\\n\\n**第三百九十四条** 地役权人应当按照合同约定支付报酬。\\n地役权人应当按照合同约定，以合理的方式利用供役地。\\n\\n**第三百九十五条** 地役权不得单独转让。土地承包经营权、建设用地使用权、宅基地使用权等权利转让的，地役权一并转让。\\n地役权不得单独抵押。土地承包经营权、建设用地使用权、宅基地使用权等权利抵押的，地役权一并抵押。\\n\\n**第三百九十六条** 地役权存续期间，供役地权利人将供役地转让、出租或者抵押的，地役权不受影响。\\n\\n**第三百九十七条** 地役权因供役地权利人将供役地转让、出租或者抵押而消灭的，地役权人有权请求赔偿损失。\\n地役权因供役地权利人将供役地转让、出租或者抵押而消灭的，地役权人可以向供役地权利人请求损害赔偿。\\n\\n**第三百九十八条** 地役权人有权依照合同约定，利用他人的不动产，以提高自己的不动产的效益。\\n前款所称他人的不动产为供役地，自己的不动产为需役地。\\n\\n###\\n</context>\\n<question>\\n私人物品什么情况下能被征用\\n</question>\\n'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "USER_PROMPT"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "a5925b48-50b1-424d-ba97-852ce0311989",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "根据提供的上下文，虽然未直接提及\"私人物品征用\"的具体条款，但可以从相关法律原则进行推论：\n",
      "\n",
      "1. **合同权利转让的限制**（第五百五十条）：\n",
      "   私人物品若涉及合同权利（如租赁物），在以下情况不得转让/征用：\n",
      "   - 根据物品性质不得转让（如个人专属用品）\n",
      "   - 有当事人约定不得转让\n",
      "   - 法律禁止转让的情形\n",
      "\n",
      "2. **占有保护原则**（第四百七十四条至第四百八十条）：\n",
      "   - 合法占有的动产受法律保护，非经法定程序不得强制征用\n",
      "   - 非法占有的物品可能被原权利人依法追索\n",
      "   - 特殊情况下（如紧急避险、公共利益需要），可能依据其他法律规定征用，但需符合：\n",
      "     • 善意取得原则（第四百七十四条）\n",
      "     • 补偿原则（第四百七十六条等规定的赔偿损失权利）\n",
      "\n",
      "3. **地役权类比参考**（第三百八十八条）：\n",
      "   若涉及不动产附属物品，可能需遵循：\n",
      "   - 合同约定优先原则\n",
      "   - 不得损害原权利人合法权益（第三百九十一条）\n",
      "\n",
      "注：完整法律依据需结合《民法典》\"物权编\"中征收征用条款（未在提供段落中显示），通常要求满足公共利益需要、依照法定权限程序、给予公平补偿三个要件。\n"
     ]
    }
   ],
   "source": [
    "response = deepseek_client.chat.completions.create(\n",
    "    model=\"deepseek-chat\",\n",
    "    messages=[\n",
    "        {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
    "        {\"role\": \"user\", \"content\": USER_PROMPT},\n",
    "    ],\n",
    ")\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af69f553-4002-4cb1-b0fd-9c0e971b2c50",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
